<script lang="tsx">
import useRender from "@/utils/hooks/render";
import {
  computed,
  defineComponent,
  reactive,
  VNode,
  watch,
  provide,
  ref,
} from "vue";
import CellItemVue from "./cell-item.vue";
import FieldItemVue from "./field-item.vue";
import { objByPath } from "./utils";

type Rule = Record<string, any>;

export type NormalItem = {
  dataIndex: string;
  valueType?: "text" | "select" | "textarea" | "file" | "date" | "time";
  title?: string;
  /**用于获取选择列表的远程的方法 */
  remote?: (modal: Record<string, any>) => Promise<any[]>;
  /**选择列表的本地数据 */
  options?: any[];
  mode?: "read" | "write";
  /**初始数据 */
  initValue?: any;
  /** 读模式下cell的属性 */
  cellProps?: Record<string, any>;
  /** 写模式下field的属性 */
  fieldProps?: Record<string, any>;
  formItemProps?: Record<string, any>;
  render?: (e: {
    currPath?: string;
    modal: Record<string, any>;
  }) => JSX.Element | VNode;
  rules?: Rule[];
  /** 读模式下不显示 */
  hideInCell?: boolean;
  /** 写模式下不显示，但还是会生成字段 */
  hideInForm?: boolean;
};

export type Column = NormalItem | GroupItem | FormListItem;

export type GroupItem = {
  mode?: "read" | "write";
  title?: string;
  valueType: "group";
  columns: Column[];
  hideInCell?: boolean;
  hideInForm?: boolean;
};

export type FormListItem = {
  mode?: "read" | "write";
  title?: string;
  dataIndex: string;
  valueType: "formList";
  initValue?: any;
  columns: Column[];
  hideInCell?: boolean;
  hideInForm?: boolean;
};
export type Item = Column & { _parentKey?: string };
export type CommmonItem = NormalItem & GroupItem & FormListItem;

const ProForm = defineComponent({
  props: {
    mode: {
      type: String as () => "read" | "write",
      default: "write",
    },
    columns: {
      type: Array as () => Column[],
      required: true,
    },
    initValue: {
      type: Object as () => Record<string, any>,
    },
  },
  setup(props, ctx) {
    const formRef = ref();
    let modalValue = reactive<Record<string, any>>({});
    provide("rootModal", modalValue);

    const changeValue = (path: string, value: any) => {
      // console.log("changeValue", value);
      objByPath(modalValue, path).set(ref(value));
    };
    provide("changeValue", changeValue);
    /**用于监听字段变化，每次变化都会初始化表单 */
    const fieldKeys = computed(() => {
      let keys: string[] = [];
      const cols = [...props.columns] as Item[];

      while (cols.length) {
        const item = cols.shift();
        if (!item) break;

        if (item.valueType === "group") {
          cols.push(...item.columns);
          continue;
        }
        if (item.valueType === "formList") {
          cols.push(
            ...item.columns.map((el) => ({ ...el, _parentKey: item.dataIndex }))
          );
        }

        keys.push(
          `${item._parentKey ? item._parentKey + ".[]." : ""}${item.dataIndex}`
        );
      }

      return keys;
    });

    const eachDataIndex = (cb: (item: NormalItem) => void) => {
      const cols = [...props.columns] as Item[];

      while (cols.length) {
        const item = cols.shift();
        if (!item) break;

        if (item.valueType === "group") {
          cols.push(...item.columns);
          continue;
        }
        if (item.valueType === "formList") {
        }

        cb(item as NormalItem);
      }
    };

    // 字段初始化
    watch(
      fieldKeys,
      () => {
        eachDataIndex((item) => {
          objByPath(modalValue, item.dataIndex).set(ref(item.initValue));
        });
      },
      { immediate: true }
    );

    // 设置初始值
    watch(
      () => props.initValue,
      (n) => {
        console.log("initValue", n);

        if (n) {
          eachDataIndex((item) => {
            objByPath(modalValue, item.dataIndex).set(
              ref(objByPath(n, item.dataIndex).get())
            );
          });
        }
      },
      { deep: true }
    );

    watch(
      () => modalValue,
      (n) => {
        console.log("modalValue update", n);
      },
      {
        deep: true,
      }
    );

    const handleValidate = () => {};

    const handleSubmit = () => {
      handleValidate();
      return modalValue;
    };

    ctx.expose({
      formRef,
      modalValue,
      handleSubmit,
      handleValidate,
    });

    useRender(() => (
      <div class="pro-form">
        <pre style={{ fontSize: "11px" }}>
          {JSON.stringify(modalValue, null, 2)}
        </pre>
        <nut-form modal-value={modalValue} ref="formRef">
          {props.mode === "write"
            ? props.columns.map((el) => {
                return <FieldItemVue item={el}></FieldItemVue>;
              })
            : props.columns.map((el) => {
                if (el.mode === "read")
                  return <CellItemVue item={el}></CellItemVue>;
              })}
        </nut-form>
      </div>
    ));

    return { fieldKeys, modalValue };
  },
});

export default ProForm;
</script>

<style lang="scss"></style>
